---
title: Popover
description: Dynamic content within a portal, activated by a button press.
---
{/* prettier-ignore-start */}
{/* prettier-ignore-end */}

import Code from '@/components/Code.astro';
import { LinkButton } from '@/components/react/LinkButton';
import { Aside, Tabs, TabItem } from '@astrojs/starlight/components';
import importedCode from '@rnr/reusables/components/ui/popover?raw';

<LinkButton href='https://rn-primitives.vercel.app/popover'>Popover Primitive</LinkButton>
<LinkButton href='/components/text'>Text Component</LinkButton>
<LinkButton target='_blank' href='https://rnr-showcase.vercel.app/popover'>
  Demo
</LinkButton>

<br />

Dynamic content within a portal, activated by a button press.

### Installation

<Tabs>
  <TabItem label='CLI'> 
    ```bash
    npx @react-native-reusables/cli@latest add popover
    ```
  </TabItem>
  <TabItem label='Manual'>
    <Aside type='tip' title='Dependencies'>
      Before copy/pasting, add the <a href='https://rn-primitives.vercel.app/popover' className='text-white font-bold'> popover primitive</a> and the <a href='/components/text' className='text-white font-bold'>text component</a> to your project.
    </Aside>

    <br />

    **Copy/paste the following code to `~/components/ui/popover.tsx`:**

    <Code code={importedCode} lang='tsx' title='~/components/ui/popover.tsx' />
  </TabItem>
</Tabs>


### Usage

<Aside type="caution">

  Requires a `<PortalHost />` as the last child of your `<Root/>` (`app/_layout.tsx`) component

  ```tsx
  import { PortalHost } from '@rn-primitives/portal';

  function Root() {
    return (
      <>
        <Stack />
        {/* Default Portal Host (one per app) */}
        <PortalHost />
      </>
    );
  }
  ```

</Aside>

```tsx
import * as React from 'react';
import { Platform, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Button } from '~/components/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '~/components/ui/popover';
import { Text } from '~/components/ui/text';

function Example() {
  const insets = useSafeAreaInsets();
  const contentInsets = {
    top: insets.top,
    bottom: insets.bottom,
    left: 12,
    right: 12,
  };

  return (
    <View className='flex-1 justify-center items-center p-6'>
      <Popover>
        <PopoverTrigger asChild>
          <Button variant='outline'>
            <Text>Open popover</Text>
          </Button>
        </PopoverTrigger>
        <PopoverContent
          side={Platform.OS === 'web' ? 'bottom' : 'top'}
          insets={contentInsets}
          className='w-80'
        >
          <Text className='font-medium leading-none native:text-xl'>Dimensions</Text>
          <Text className='text-sm text-muted-foreground'>
            Set the dimensions for the layer.
          </Text>
        </PopoverContent>
      </Popover>
    </View>
  );
}
```

## Props

### Popover

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |     Note     |
| :----------: | :----------------------: | :----------: |
|   asChild    |         boolean          | _(optional)_ |
| onOpenChange| (value: boolean) => void |                         |

### PopoverTrigger

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |

### PopoverContent

Extends [`View`](https://reactnative.dev/docs/view#props) props

|         Prop         |        Type         |         Note          |
| :------------------: | :-----------------: | :-------------------: |
|       asChild        |       boolean       |     _(optional)_      |
|      forceMount      |  true \| undefined  |     _(optional)_      |
|       alignOffset       |                    number                    | Native Only _(optional)_       |
|         insets          |                    Insets                    | Native Only _(optional)_       |
|     avoidCollisions     |                   boolean                    | Native Only _(optional)_       |
|          align          |         'start' \| 'center' \| 'end'         | Native Only _(optional)_       |
|          side           |              'top' \| 'bottom'               | Native Only _(optional)_       |
|       sideOffset        |                    number                    | Native Only _(optional)_       |
| disablePositioningStyle |                   boolean                    | Native Only _(optional)_ |
|   onOpenAutoFocus    | (ev: Event) => void | Web Only _(optional)_ |
|   onCloseAutoFocus   | (ev: Event) => void | Web Only _(optional)_ |
|   onEscapeKeyDown    | (ev: Event) => void | Web Only _(optional)_ |
|  onInteractOutside   | (ev: Event) => void | Web Only _(optional)_ |
| onPointerDownOutside | (ev: Event) => void | Web Only _(optional)_ |
